/*
Copyright 2010 Iain Surgey.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/


#__body__

private var load_images : Vector<LoadImg>;
private var cur_loadimg : Int;

private function PushImage(name : String, texinfo : Int) {
	
	if (name == null || name == "common/caulk" || name == "radiant/notex" || name == "NULL" ||
	name == "clip" || name == "clip_mon" || name == "hint" || name == "trigger") return;
	
	name = name.substr(5);
	
	// look for it
	for ( i in 0...load_images.length )
	{
		if (load_images[i].name == name)
		{
			load_images[i].texinfo[load_images[i].texinfo.length] = texinfo;
			return;
		}
	}
	
	var img = new LoadImg();
	img.name = name;
	img.texinfo[0] = texinfo;
	load_images[load_images.length] = img;
}


private function LoadImages() {
	if (load_images.length > 0) {
		cur_loadimg = 0;
		flash.Lib.current.stage.addEventListener( Event.ENTER_FRAME, LoadImageOnFrame );
	}
}

private function LoadImageOnFrame( e : Event ) {
	#{d| mtexinfo_t *ti}
	#{d| int iptr}
	
	var img = load_images[cur_loadimg];
	iptr = LoadGrb (img.name, haxe.Resource.getBytes(img.name).getData());
	
	for (i in 0...img.texinfo.length) {
		ti = img.texinfo[i];
		#{ti->image = iptr};
	}
	
	scrtxt.text = "";
	write("["+cur_loadimg+"/"+load_images.length+"] Loaded: "+img.name+".grb");
	
	cur_loadimg++;
	
	if (cur_loadimg >= load_images.length) {
		flash.Lib.current.stage.removeEventListener( Event.ENTER_FRAME, LoadImageOnFrame );
		render_main2();
	}
	
}


/*
===============
R_FindImage

Finds or loads the given image
===============
*/
private function R_FindImage(name : String, type : Int) {
	
	#{d| image_t	*image}
	#{d| int		i, j, len, width, height}
	
	/*trace(name);
	
	return -1;*/
	
	if (name == null || name == "common/caulk" || name == "radiant/notex" || name == "NULL")
		return -1;
	
	if (type == IT_WALL) {
		name = name.substr(5); }
		
	if (name == "clip" || name == "clip_mon" || name == "hint" || name == "trigger") return -1;
	
	// look for it
	for ( i in 0...r_images.length )
	{
		if (r_images[i].name == name)
		{
			return r_images[i].ptr;
		}
	}
	
	/*if (type == IT_WALL) {
		return LoadGrb (name, haxe.Resource.getBytes(name).getData());
	}*/
	
	if (type == IT_SKY) {
		var pic : ByteArray = new ByteArray();
		
		LoadTGA (name, pic);
		if (pic.length < 1) {
			Sys_Error (ERR_DROP, "R_FindImage: can't load "+name);
		}
		
		image = GL_LoadPic (name, pic, pcx_width, pcx_height, type);
		return image;
	}
	
	if (type == IT_SKIN) {
		var pic : ByteArray = new ByteArray();
		var palette : ByteArray = new ByteArray();
		
		LoadTGA (name, pic);
		if (pic.length < 1) {
			Sys_Error (ERR_DROP, "R_FindImage: can't load "+name);
		}
		image = GL_LoadPic (name, pic, pcx_width, pcx_height, type);
		
		return image;
	}

	return -1;
}

/*
================
GL_LoadPic

================
*/
private function GL_LoadPic (name : String, pic : ByteArray, width : Int, height : Int, itype : Int) : Int
{
	#{s| int width, height, itype}
	#{d| image_t *image}
	#{d| int c}
	
	image = #{m| sizeof(image_t)};
	
	#{image->width = width};
	#{image->height = height};
	#{image->type = itype};
	
	c = width*height*4;
	#{image->pixels[0] = #[__m__.length]#};
	pic.position = 0;
	
	__m__.position = __m__.length;
	__m__.writeBytes(pic,0,c);
	
	var img : ImgName = new ImgName();
	img.name = name;
	img.ptr = image;
	r_images[r_images.length] = img;	
	
	return image;
}


/*
=============
LoadTGA
=============
*/
private function LoadTGA (name : String, pixbuf : ByteArray)
{
	#{d| int		columns, rows, numPixels}
	#{d| int		row, column}
	var buf_p : ByteArray;
	#{d| int		length}
	
	#{d| int 	id_length, colormap_type, image_type}
	#{d| int	colormap_index, colormap_length}
	#{d| int	colormap_size}
	#{d| int	x_origin, y_origin, width, height}
	#{d| int	pixel_size, attributes}
	
	#{d| int red,green,blue,alphabyte,packetHeader,packetSize,j}
	
	var breakOut : Bool = false;
	var top : Bool = false;
	
	buf_p = haxe.Resource.getBytes(name).getData();
	buf_p.endian = Endian.LITTLE_ENDIAN;
	
	if (buf_p == null)
	{
		Sys_Error (ERR_DROP, "Bad tga file "+name);
		return;
	}
	
	id_length = buf_p.readUnsignedByte();
	colormap_type = buf_p.readUnsignedByte();
	image_type = buf_p.readUnsignedByte();
	
	colormap_index = buf_p.readShort();
	colormap_length = buf_p.readShort();
	colormap_size = buf_p.readUnsignedByte();
	x_origin = buf_p.readShort();
	y_origin = buf_p.readShort();
	width = buf_p.readUnsignedShort();
	height = buf_p.readUnsignedShort();
	pixel_size = buf_p.readUnsignedByte();
	attributes = buf_p.readUnsignedByte();
	
	if (image_type!=2 && image_type!=10) { trace(image_type);
		Sys_Error (ERR_DROP, "LoadTGA: Only type 2 and 10 targa RGB images supported\n"); }
	
	if (colormap_type !=0 || (pixel_size!=32 && pixel_size!=24))
		Sys_Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
	
	columns = width;
	rows = height;
	numPixels = columns * rows;
	
	red = 255;
	green = 255;
	blue = 255;
	alphabyte = 255;
	
	if (id_length != 0)
		buf_p.position += id_length;  // skip TARGA image comment
	
	pixbuf.length = numPixels*4;
	pixbuf.position = 0;
	
	if (((attributes&0x20)>>5) == 0) {
		top = true;
	}
	
	if (image_type==2) {  // Uncompressed, RGB images
		row = rows;
		while(--row>=0) {
			if (top) pixbuf.position = row*columns*4;
			column = -1;
			while(++column<columns) {
				switch (pixel_size) {
					case 24:
						blue = buf_p.readUnsignedByte();
						green = buf_p.readUnsignedByte();
						red = buf_p.readUnsignedByte();
						alphabyte = 255;
						pixbuf.writeByte(blue);
						pixbuf.writeByte(green);
						pixbuf.writeByte(red);
						pixbuf.writeByte(alphabyte);
					case 32:
						blue = buf_p.readUnsignedByte();
						green = buf_p.readUnsignedByte();
						red = buf_p.readUnsignedByte();
						alphabyte = buf_p.readUnsignedByte();
						pixbuf.writeByte(blue);
						pixbuf.writeByte(green);
						pixbuf.writeByte(red);
						pixbuf.writeByte(alphabyte);
				}
			}
		}
	}
	else if (image_type==10) {   // Runlength encoded RGB images
		row = rows;
		while(--row>=0) {
			if (top) pixbuf.position = row*columns*4;
			column = 0;
			while(column<columns) {
				packetHeader= buf_p.readUnsignedByte();
				packetSize = 1 + (packetHeader & 0x7f);
				if ((packetHeader & 0x80) != 0) {        // run-length packet
					switch (pixel_size) {
						case 24:
							blue = buf_p.readUnsignedByte();
							green = buf_p.readUnsignedByte();
							red = buf_p.readUnsignedByte();
							alphabyte = 255;
						case 32:
							blue = buf_p.readUnsignedByte();
							green = buf_p.readUnsignedByte();
							red = buf_p.readUnsignedByte();
							alphabyte = buf_p.readUnsignedByte();
					}
	
					for(j in 0...packetSize) {
						pixbuf.writeByte(blue);
						pixbuf.writeByte(green);
						pixbuf.writeByte(red);
						pixbuf.writeByte(alphabyte);
						column++;
						if (column==columns) { // run spans across rows
							column=0;
							if (row>0)
								row--;
							else {
								breakOut = true;
								break;
							}
							if (top) pixbuf.position = row*columns*4;
						}
					}
				}
				else {                            // non run-length packet
					for(j in 0...packetSize) {
						switch (pixel_size) {
							case 24:
								blue = buf_p.readUnsignedByte();
								green = buf_p.readUnsignedByte();
								red = buf_p.readUnsignedByte();
								alphabyte = 255;
								pixbuf.writeByte(blue);
								pixbuf.writeByte(green);
								pixbuf.writeByte(red);
								pixbuf.writeByte(alphabyte);
							case 32:
								blue = buf_p.readUnsignedByte();
								green = buf_p.readUnsignedByte();
								red = buf_p.readUnsignedByte();
								alphabyte = buf_p.readUnsignedByte();
								pixbuf.writeByte(blue);
								pixbuf.writeByte(green);
								pixbuf.writeByte(red);
								pixbuf.writeByte(alphabyte);
						}
						column++;
						if (column==columns) { // pixel packet run spans across rows
							column=0;
							if (row>0)
								row--;
							else {
								breakOut = true;
								break;
							}
							if (top) pixbuf.position = row*columns*4;
						}						
					}
				}
				if (breakOut) break;
			}
			if (breakOut) break;
		}
	}
	
	pcx_width = width;
	pcx_height = height;
}

private function LoadGrb (name : String, imgbytes : ByteArray) : Int {
	#{d| int width, height, len, pixel}
	
	imgbytes.uncompress();
	imgbytes.endian = Endian.LITTLE_ENDIAN;
	var pixbuf = new ByteArray();
	
	width = imgbytes.readUnsignedShort();
	height = imgbytes.readUnsignedShort();
	len = width*height*2;
	
	if ( len+4 != imgbytes.length) {
		Sys_Error (ERR_DROP, "Bad grb file "+name);
		return -1;
	}
	
	for ( i in 0...len>>1 ) {
		pixel = imgbytes.readUnsignedShort();
		pixbuf.writeByte( ((pixel&0x1F)<<3) );
		pixbuf.writeByte( ((pixel&0xFC00)>>8) );
		pixbuf.writeByte( ((pixel&0x3E0)>>2) );
		pixbuf.writeByte(0xFF);
	}
	
	var imgp = CalcMipLevels_16(width,height,pixbuf);
	
	var img = new ImgName();
	img.name = name;
	img.ptr = imgp;
	r_images[r_images.length] = img;
	
	return imgp;
}


/*
=============
LoadTGA
=============
*/
private function LoadTGA_16 (name : String) : Int
{
	#{d| int		columns, rows, numPixels}
	#{d| int		row, column}
	var buf_p : ByteArray;
	#{d| int		length}
	
	#{d| int 	id_length, colormap_type, image_type}
	#{d| int	colormap_index, colormap_length}
	#{d| int	colormap_size}
	#{d| int	x_origin, y_origin, width, height}
	#{d| int	pixel_size, attributes}
	
	#{d| int red,green,blue,packetHeader,packetSize,j}
	
	var breakOut : Bool = false;
	var top : Bool = false;
	var pixbuf = new ByteArray();
	
	var class_bytes = Type.resolveClass(name);
	buf_p = Type.createInstance(class_bytes, []);
	buf_p.endian = Endian.LITTLE_ENDIAN;
	
	if (buf_p == null)
	{
		Sys_Error (ERR_DROP, "Bad tga file "+name);
		return -1;
	}
	
	id_length = buf_p.readUnsignedByte();
	colormap_type = buf_p.readUnsignedByte();
	image_type = buf_p.readUnsignedByte();
	
	colormap_index = buf_p.readShort();
	colormap_length = buf_p.readShort();
	colormap_size = buf_p.readUnsignedByte();
	x_origin = buf_p.readShort();
	y_origin = buf_p.readShort();
	width = buf_p.readUnsignedShort();
	height = buf_p.readUnsignedShort();
	pixel_size = buf_p.readUnsignedByte();
	attributes = buf_p.readUnsignedByte();
	
	if (image_type!=2 && image_type!=10) 
		Sys_Error (ERR_DROP, "LoadTGA: Only type 2 and 10 targa RGB images supported\n");
	
	if (colormap_type !=0 || (pixel_size!=32 && pixel_size!=24))
		Sys_Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
	
	columns = width;
	rows = height;
	numPixels = columns * rows;
	
	red = 255;
	green = 255;
	blue = 255;
	
	if (id_length != 0)
		buf_p.position += id_length;  // skip TARGA image comment
	
	pixbuf.length = numPixels*4;
	pixbuf.position = 0;
	
	if (((attributes&0x20)>>5) == 0) {
		top = true;
	}
	
	if (image_type==2) {  // Uncompressed, RGB images
		row = rows;
		while(--row>=0) {
			if (top) pixbuf.position = row*columns*4;
			column = -1;
			while(++column<columns) {
				switch (pixel_size) {
					case 24:
						blue = buf_p.readUnsignedByte();
						green = buf_p.readUnsignedByte();
						red = buf_p.readUnsignedByte();
						pixbuf.writeByte(blue);
						pixbuf.writeByte(green);
						pixbuf.writeByte(red);
						pixbuf.writeByte(0xFF);
					case 32:
						blue = buf_p.readUnsignedByte();
						green = buf_p.readUnsignedByte();
						red = buf_p.readUnsignedByte();
						buf_p.position += 1;
						pixbuf.writeByte(blue);
						pixbuf.writeByte(green);
						pixbuf.writeByte(red);
						pixbuf.writeByte(0xFF);
				}
			}
		}
	}
	
	var imgp = CalcMipLevels_16(width,height,pixbuf);
	
	var img = new ImgName();
	img.name = name;
	img.ptr = imgp;
	r_images[r_images.length] = img;
	
	return imgp;
}

private function CalcMipLevels_16( width : Int, height : Int, pixbuf : ByteArray ) : Int {
	#{d| int ptr0}
	#{d| int green, red, blue}
	#{d| image_t *image}
	
	image = #{m| sizeof(image_t)};
	
	#{image->width = width};
	#{image->height = height};
	#{image->type = IT_WALL};
	
	var mtx = new flash.geom.Matrix();
	var mip0 = new BitmapData(width,height,false,0x000000);
	var mip1 = new BitmapData(width>>1,height>>1,false,0x000000);
	var mip2 = new BitmapData(width>>2,height>>2,false,0x000000);
	var mip3 = new BitmapData(width>>3,height>>3,false,0x000000);
	
	pixbuf.position = 0;
	pixbuf.endian = __m__.endian;
	mip0.setPixels(new flash.geom.Rectangle(0,0,width,height),pixbuf);
	
	ptr0 = __m__.length;
	#{image->pixels[0] = ptr0};
	__m__.length += pixbuf.length>>1;
	
	pixbuf.position = 0;
	for (i in 0...(pixbuf.length>>2)) {
		blue = pixbuf.readUnsignedByte();
		green = pixbuf.readUnsignedByte();
		red = pixbuf.readUnsignedByte();
		pixbuf.position += 1;
		Memory.setI16( ptr0 + (i<<1) , ((green&0xFC)<<8) | ((red&0xF8)<<2) | ((blue&0xF8)>>3) );
	}
	pixbuf.length = 0;
	pixbuf = null;
	
	mtx.identity();
	mtx.scale(0.5,0.5);
	mip1.draw(mip0,mtx,null,null,null,true);
	pixbuf = mip1.getPixels(mip1.rect);
	
	ptr0 = __m__.length;
	#{image->pixels[1] = ptr0};
	__m__.length += pixbuf.length>>1;
	
	pixbuf.position = 0;
	for (i in 0...(pixbuf.length>>2)) {
		pixbuf.position += 1;
		red = pixbuf.readUnsignedByte();
		green = pixbuf.readUnsignedByte();
		blue = pixbuf.readUnsignedByte();
		Memory.setI16( ptr0 + (i<<1) , ((green&0xFC)<<8) | ((red&0xF8)<<2) | ((blue&0xF8)>>3) );
	}
	pixbuf.length = 0;
	pixbuf = null;
	
	
	mtx.identity();
	mtx.scale(0.5,0.5);
	mip2.draw(mip1,mtx,null,null,null,true);
	pixbuf = mip2.getPixels(mip2.rect);
	
	ptr0 = __m__.length;
	#{image->pixels[2] = ptr0};
	__m__.length += pixbuf.length>>1;
	
	pixbuf.position = 0;
	for (i in 0...(pixbuf.length>>2)) {
		pixbuf.position += 1;
		red = pixbuf.readUnsignedByte();
		green = pixbuf.readUnsignedByte();
		blue = pixbuf.readUnsignedByte();
		Memory.setI16( ptr0 + (i<<1) , ((green&0xFC)<<8) | ((red&0xF8)<<2) | ((blue&0xF8)>>3) );
	}
	pixbuf.length = 0;
	pixbuf = null;
	
	
	mtx.identity();
	mtx.scale(0.5,0.5);
	mip3.draw(mip2,mtx,null,null,null,true);
	pixbuf = mip3.getPixels(mip3.rect);
	
	ptr0 = __m__.length;
	#{image->pixels[3] = ptr0};
	__m__.length += pixbuf.length>>1;
	
	pixbuf.position = 0;
	for (i in 0...(pixbuf.length>>2)) {
		pixbuf.position += 1;
		red = pixbuf.readUnsignedByte();
		green = pixbuf.readUnsignedByte();
		blue = pixbuf.readUnsignedByte();
		Memory.setI16( ptr0 + (i<<1) , ((green&0xFC)<<8) | ((red&0xF8)<<2) | ((blue&0xF8)>>3) );
	}
	pixbuf.length = 0;
	pixbuf = null;
	
	//IMPORTANT!!!!!!!!!!!!!!!!!!!!!
	mip0.dispose();
	mip1.dispose();
	mip2.dispose();
	mip3.dispose();
	mip0 = null;
	mip1 = null;
	mip2 = null;
	mip3 = null;	
	
	return image;
}



